# -*- coding: utf-8 -*-
# @Time    : 2018/5/31 下午10:55
# @Author  : Lavn
# @Email   : 959875529@qq.com
# @File    : ClassDemo.py
# @Software: PyCharm

#Python 是一门面向对象的语言, 面向对象是一种抽象，抽象是指用分类的眼光去看世界的一种方法
#万事万物皆对象。也就是说在面向对象中，把构成问题事务分解成各个对象。
#面向对象有三大特性，封装、继承和多态。


#类
#用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

#对象
#通过类定义的数据结构实例

#继承
#即一个派生类（derived class）继承基类（base class）的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
#例如：一个 Dog 类型的对象派生自 Animal 类，这是模拟"是一个（is-a）"关系（例图，Dog 是一个 Animal ）

#多态
#它是指对不同类型的变量进行相同的操作，它会根据对象（或类）类型的不同而表现出不同的行为。

#封装性
#封装”就是将抽象得到的数据和行为（或功能）相结合，形成一个有机的整体（即类）；
#封装的目的是增强安全性和简化编程，使用者不必了解具体的实现细节，而只是要通过外部接口，一特定的访问权限来使用类的成员。


#类例子
#class ClassName:
#    <statement-1>
#    .
#    .
#    .
#    <statement-N>

#一个类也是由属性和方法组成的，有些时候我们定义类的时候需要设置类的属性，因此这就需要构造函
#类的构造函数如下：
#def __init__(self,[...):
#析构函数语法如下：
#def __del__(self,[...):

# class Test:
#     def prt(self):
#         print('haha')
#         print(self)
#         print(self.__class__)
#
# t = Test()
# t.prt()
# print('\n')

# # 旧式类
# class OldClass:
#     def __init__(self, account, name):
#         self.account = account;
#         self.name = name;
#
#
# # 新式类
# class NewClass(object):
#     def __init__(self, account, name):
#         self.account = account;
#         self.name = name;
#
# if __name__ == '__main__':
#     old_class = OldClass(111111, 'OldClass')
#     print(old_class)
#     print(type(old_class))
#     print(dir(old_class))
#     print('\n')
#     new_class=NewClass(222222,'NewClass')
#     print(new_class)
#     print(type(new_class))
#     print(dir(new_class))
#仔细观察输出的结果，对比一下，就能观察出来，注意喔，Pyhton3 中输出的结果是一模一样的，因为Python3 中没有新式类旧式类的问题。


#类属性
#直接定义
# class UserInfo(object):
#     name='两点水'
#
# t = UserInfo()
# print(t.name)
# print('\n')


#在构造中定义
# class UserInfo(object):
#     def __init__(self,name,age):
#         self.name=name
#         self.__age = age
#
# t = UserInfo('多大的',11)
# print(t.name)
# #吧age 变成了 USERinfo_age
# print(t.__dict__)


#类方法
#类创建包含方法  基类里面
#__init__  构造函数，在生成对象时调用
#__del__   析构函数，释放对象时使用
#__repr__  打印，转换
#__setitem__  按照索引赋值
#__getitem__  按照索引获取值
#__len__  获得长度
#__cmp__      比较运算
#__call__  函数调用
#__add__  加运算
#__sub__  减运算
#__mul__  乘运算
#__div__  除运算
#__mod__  求余运算
#__pow__  乘方


# type(obj)：来获取对象的相应类型；
# isinstance(obj, type)：判断对象是否为指定的 type 类型的实例；
# hasattr(obj, attr)：判断对象是否具有指定属性/方法；
# getattr(obj, attr[, default]) 获取属性/方法的值, 要是没有对应的属性则返回 default 值（前提是设置了 default），否则会抛出 AttributeError 异常；
# setattr(obj, attr, value)：设定该属性/方法的值，类似于 obj.attr=value；
# dir(obj)：可以获取相应对象的所有属性和方法名的列表：


#其实我们也可以把方法看成是类的属性的，那么方法的访问控制也是跟属性是一样的，也是没有实质上的私有方法。一切都是靠程序员自觉遵守 Python 的编程规范。
# class User(object):
#     def upgrade(self):
#         pass
#
#     def _buy_equipment(self):
#         pass
#
#     def __pk(self):
#         pass


# @classmethod 调用的时候直接使用类名类调用，而不是某个对象
# @property 可以像访问属性一样调用方法

# class UserInfo(object):
#     lv = 5
#
#     def __init__(self, name, age, account):
#         self.name = name
#         self._age = age
#         self.__account = account
#
#     def get_account(self):
#         return self.__account
#
#     def __repr__(self):
#         return 'UserInfo(%s)' % self.name
#
#     @classmethod
#     def get_name(cls):
#         return cls.lv
#
#     @property
#     def get_age(self):
#         return self._age
#
#
# if __name__ == '__main__':
#     userInfo = UserInfo('两点水', 23, 347073565);
#     # 打印所有属性
#     print(dir(userInfo))
#     # 打印构造函数中的属性
#     print(userInfo.__dict__)
#     # 直接使用类名类调用，而不是某个对象
#     print(UserInfo.lv)
#     # 像访问属性一样调用方法（注意看get_age是没有括号的）
#     print(userInfo.get_age)
#     print(userInfo.__repr__())


